Skip to content

Refactor lexer state management to use save/restore pattern#245

Merged
bartveneman merged 1 commit into
mainfrom
claude/reuse-lexer-instance-2ibLX
May 17, 2026
Merged

Refactor lexer state management to use save/restore pattern#245
bartveneman merged 1 commit into
mainfrom
claude/reuse-lexer-instance-2ibLX

Conversation

@bartveneman
Copy link
Copy Markdown
Member

@bartveneman bartveneman commented May 17, 2026

Summary

Eliminates per-call Lexer allocations in the hot paths of SelectorParser and AtRulePreludeParser:

  • ANplusBParser in parse_nth_expression() — was allocating a new ANplusBParser (and therefore a new Lexer) for every :nth-child(), :nth-of-type(), etc. encountered. Promoted to a field on SelectorParser, initialized once in the constructor.
  • Temp Lexer in parse_lang_identifiers() — replaced new Lexer() + reference swap with lexer.save_position() / restore_position().
  • Temp Lexer in parse_feature_value() — same save/restore replacement.

Benchmark results

Tested against main (Bootstrap 273 KB, Tailwind 3.5 MB). ops/sec, higher is better.

Task main this PR Δ
Parser — Large CSS (3 KB) 7 550 9 236 +22%
Parser — Bootstrap CSS (274 KB) 88 104 +18%
Parser — Tailwind CSS (3.5 MB) 6 7 +13%
Parse/walk — Bootstrap CSS 81 96 +18%
Parse/walk — Tailwind CSS 6 7 +14%

Tokenizer-only benchmarks are unchanged (expected — these changes only affect the selector and prelude parsers).

https://claude.ai/code/session_01CQeKNnXidD5EQVJY4xBMMp

…restore

- Move ANplusBParser from per-call allocation in parse_nth_expression() to a
  field on SelectorParser, initialized once in the constructor. This avoids
  allocating a new Lexer for every :nth-child()/:nth-of-type() etc. encountered.

- Replace the temporary `new Lexer()` in SelectorParser.parse_lang_identifiers()
  and AtRulePreludeParser.parse_feature_value() with lexer.save_position() /
  restore_position(). The saved LexerPosition object is a plain struct with no
  heap cost beyond the object itself, and avoids re-allocating a full Lexer +
  re-initializing its source reference for each :lang() argument range and each
  media-feature value range.

https://claude.ai/code/session_01CQeKNnXidD5EQVJY4xBMMp
@codecov-commenter
Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 18 bytes (0.01%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
@projectwallace/css-parser-esm 189.4kB 18 bytes (0.01%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: @projectwallace/css-parser-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
parse-atrule-prelude.js -30 bytes 22.7kB -0.13%
parse-selector.js 22 bytes 19.16kB 0.11%
parse-selector.d.ts 26 bytes 1.43kB 1.85%

Files in parse-atrule-prelude.js:

  • ./src/parse-atrule-prelude.ts → Total Size: 22.26kB

Files in parse-selector.js:

  • ./src/parse-selector.ts → Total Size: 18.61kB

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.14%. Comparing base (af69d75) to head (ae1841c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #245      +/-   ##
==========================================
- Coverage   93.15%   93.14%   -0.01%     
==========================================
  Files          17       17              
  Lines        3038     3035       -3     
  Branches      845      845              
==========================================
- Hits         2830     2827       -3     
  Misses        208      208              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bartveneman bartveneman merged commit 2f19177 into main May 17, 2026
5 checks passed
@bartveneman bartveneman deleted the claude/reuse-lexer-instance-2ibLX branch May 17, 2026 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants